/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       hire_hero_dialog.cpp

	$Header: /game/hire_hero_dialog.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "hire_hero_dialog.h"

#include "adaptor_handler.h"
#include "adventure_map.h"
#include "bitmap_layer_window.h"
#include "bitmap_group_cache.h"
#include "bound_handler.h"
#include "button_cache.h"
#include "enum_operations.h"
#include "external_string.h"
#include "format_string.h"
#include "hero.h"
#include "hero_class_properties.h"
#include "hero_portrait.h"
#include "interface_help.h"
#include "material_names.h"
#include "random.h"
#include "scrollbar.h"
#include "skill_icon.h"
#include "skill_properties.h"
#include "standard_fonts.h"
#include "text_window.h"
#include "text_edit_window.h"
#include "toggle_button.h"
#include "town_properties.h"

static t_bitmap_group_cache g_layout( "dialog.hire_hero" );

extern t_external_string const k_hotkey_buy;
extern t_button_cache const k_buy_button;
extern t_button_cache		g_checkbox;
extern t_button_cache const	k_close_button;
static t_external_string const k_text_tavern( "tavern.misc" );
static t_external_string const k_text_male( "tavern_male.text" );
static t_external_string const k_text_female( "tavern_female.text" );

// ---------------------------------------------------------
// dialog for hiring heroes
// ---------------------------------------------------------
t_hire_hero_dialog::t_hire_hero_dialog( int const* hire_costs, int funds, 
									    t_adventure_map const& map )
                  : t_dialog_box( 0 ), m_map( map )
{
	int i;
	t_help_block const&		help = get_help_block( "tavern" );

	for (i = 0; i < k_hero_class_basic_count; i++)
		m_hero[i].cost = hire_costs[i];

	m_funds = funds;
	m_layout = g_layout.get();

	// add background layer
	t_bitmap_layer const* layer;
	t_window*             window;

	layer = m_layout->find( "background" );
	window = new t_bitmap_layer_window( layer, t_screen_point(0,0), this );

	// create selected image
	t_screen_rect rect;

	rect = m_layout->find( "selected_portrait" )->get_rect();
	m_selected_portrait = new t_bitmap_layer_window( 0, rect.top_left(), this );

	// add scrollbar to select hero image
	rect = m_layout->find( "scrollbar" )->get_rect();
	m_scrollbar = new t_scrollbar( rect.top_left(), rect.height(), this, 0, 0 );
	m_scrollbar->set_handler( bound_handler( *this, &t_hire_hero_dialog::portrait_change ) );

	// add checkboxes for sex
	t_text_window* text_window;

	rect = m_layout->find( "male_checkbox" )->get_rect();
	m_male_checkbox = new t_toggle_button( g_checkbox.get(), rect.top_left(), this, true );
	m_male_checkbox->set_click_handler( add_2nd_argument( 
		             bound_handler( *this, &t_hire_hero_dialog::sex_selected ), true ) );
	m_sex_group.add( m_male_checkbox );

	rect = m_layout->find( "male_text" )->get_rect();
	//text_window = new t_text_window( get_font( rect.height() ), rect, this, k_text_male,
	text_window = new t_text_window( get_font( 18 ), rect, this, k_text_male,
		                             t_pixel_24( 0,0,0 ) );
	text_window->set_drop_shadow( true, t_pixel_24(200,200,200) );

	rect = m_layout->find( "female_checkbox" )->get_rect();
	m_female_checkbox = new t_toggle_button( g_checkbox.get(), rect.top_left(), this, true );
	m_female_checkbox->set_click_handler( add_2nd_argument( 
		               bound_handler( *this, &t_hire_hero_dialog::sex_selected ), false ) );
	m_sex_group.add( m_female_checkbox );

	rect = m_layout->find( "female_text" )->get_rect();
	//text_window = new t_text_window( get_font( rect.height() ), rect, this, k_text_female,
	text_window = new t_text_window( get_font( 18 ), rect, this, k_text_female,
		                             t_pixel_24(0,0,0) );
	text_window->set_drop_shadow( true, t_pixel_24(200,200,200) );

	// add name window
	t_text_edit_handler edit_handler;

	rect = m_layout->find( "hero_name" )->get_rect();
	m_name_window = new t_text_edit_window( get_font( rect.height() ), rect, this, "",
		                             t_pixel_24(0,0,0) );
	edit_handler = bound_handler( *this, &t_hire_hero_dialog::name_change );
	m_name_window->set_end_edit_handler( edit_handler );
	m_name_window->set_drop_shadow( true, t_pixel_24(200,200,200));
	m_name_window->set_center_horizontal();

	// add hero class text
	rect = m_layout->find( "hero_class" )->get_rect();
	m_class_text = new t_text_window( get_font( 18 ), rect, this, "",
	//m_class_text = new t_text_window( get_font( rect.height() ), rect, this, "",
		                              t_pixel_24(0,0,0) );
	m_class_text->set_drop_shadow( true, t_pixel_24(200,200,200) );
	m_class_text->set_center_horizontal();

	// add title
	rect = m_layout->find( "title" )->get_rect();
	text_window = new t_text_window( get_font( rect.height() ), rect, this, 
		                             k_text_tavern, t_pixel_24(0,0,0));
	text_window->set_drop_shadow( false );
	text_window->set_center_horizontal();
	
	// create windows for starting skills
	std::string name;

	for (i = 0; i < 3; i++)
	{
		name = format_string( "skill_%i", i + 1 );
		rect = m_layout->find( name )->get_rect();
		m_skill_icons[i] = new t_skill_icon( t_skill(), rect, this );
		m_skill_icons[i]->set_visible( false );
	}

	// add biography
	rect = m_layout->find( "biography" )->get_rect();
	m_biography_window = new t_text_window( get_font( 20 ), rect, this, "", t_pixel_24( 0,0,0 ) );
	m_biography_window->set_drop_shadow( true, t_pixel_24(200,200,200) );

	// add gold icon & number
	layer = m_layout->find( "gold" );
	window = new t_bitmap_layer_window( layer, t_screen_point(0,0), this );
	window->set_help_balloon_text( k_material_name[k_gold] );

	rect = m_layout->find( "gold_number" )->get_rect();
	m_cost_text = new t_text_window( get_font( rect.height() ), rect, this, "2000", 
		                             t_pixel_24(0,0,0) );
	m_cost_text->set_drop_shadow( true, t_pixel_24(200,200,200) );
	m_cost_text->set_center_horizontal();

	// add buy and cancel
	t_button* button;

	layer = m_layout->find( "buy_button" );
	m_buy_button = new t_button( k_buy_button.get(), layer->get_rect().top_left(), this );
	add_close_button( m_buy_button, 1 );
	set_help( m_buy_button, help, "purchase" );

	layer = m_layout->find( "ok_button" );
	button = new t_button( k_close_button.get(), layer->get_rect().top_left(), this );
	add_close_button( button, 0 );
	set_help( button, help, "cancel" );

    // Magic/might highlights
	layer = m_layout->find( "might_highlight" );
    m_might_magic_offset = m_layout->find("knight_portrait")->get_rect().top_left() - layer->get_rect().top_left();
	m_selected_might_ring = new t_bitmap_layer_window( layer, -layer->get_rect().top_left(), this );
	m_selected_might_ring->set_visible( false );

	layer = m_layout->find( "magic_highlight" );
	m_selected_magic_ring = new t_bitmap_layer_window( layer, -layer->get_rect().top_left(), this );
	m_selected_magic_ring->set_visible( false );

	// create class buttons
	create_class_buttons();

	// add foreground
	layer = m_layout->find( "foreground" );
	window = new t_bitmap_layer_window( layer, t_screen_point(0,0), this );

	layer = m_layout->find( "selected_ring" );
	window = new t_bitmap_layer_window( layer, t_screen_point(0,0), this );

	layer = m_layout->find( "skill_frame" );
	window = new t_bitmap_layer_window( layer, t_screen_point(0,0), this );

	m_selected_might_ring->move_to_front();
	m_selected_magic_ring->move_to_front();

	// find window size
	t_screen_rect window_size = m_layout->get_rect();
	t_window*     parent = get_parent();

	// initialize the dialog
	window_size += t_screen_point( (parent->get_width() - window_size.width()) / 2, 
		                           (parent->get_height() - window_size.height()) / 2 );
	init( window_size );
}

// ---------------------------------------------------------
// dialog for hiring heroes
// ---------------------------------------------------------
void t_hire_hero_dialog::create_class_buttons()
{
	t_hero_class  hero_class;
	t_screen_rect rect;
	t_button*     button;
	std::vector<t_default_hero> male_list;
	std::vector<t_default_hero> female_list;
	std::vector<t_hero_class>   classes;
	int                         minimum_cost = 32767;

	for (hero_class = t_hero_class(0); hero_class < k_hero_class_basic_count; enum_incr(hero_class))
	{
		t_hero_data& hero = m_hero[hero_class];

		if (hero.cost == 0)
			continue;

		male_list = m_map.get_unused_heroes( hero_class, true );
		female_list = m_map.get_unused_heroes( hero_class, false );
		hero.is_male = male_list.size() > female_list.size()
					   || (male_list.size() == female_list.size() && random(0,1) == 0 );
		if (hero.is_male)
			hero.heroes.swap( male_list );
		else
			hero.heroes.swap( female_list );

		hero.selected = random( hero.heroes.size() );
		hero.portrait = get_hero_portrait( hero.heroes[hero.selected].portrait_id, 52 );

		rect = m_layout->find( get_keyword( hero_class ) + "_portrait" )->get_rect();

		button = new t_button( rect.top_left(), this );
		hero.portrait_window = new t_bitmap_layer_window( hero.portrait.get(), 
			                                              t_screen_point(0,0), button, 
			                                              false );
		button->set_released_image( hero.portrait_window );
		button->set_help_balloon_text( get_class_name( hero_class ));
		button->set_click_handler( add_2nd_argument( 
			bound_handler( *this, &t_hire_hero_dialog::class_selected ), hero_class ) );
		if (hero.cost < minimum_cost)
		{
			classes.clear();
			minimum_cost = hero.cost;
		}
		if (hero.cost <= minimum_cost)
			classes.push_back( hero_class );
	}

	// choose an initial class to select
	class_selected( 0, classes[ random( classes.size() ) ] );
}

// ---------------------------------------------------------
// dialog for hiring heroes
// ---------------------------------------------------------
void t_hire_hero_dialog::class_selected( t_button*, t_hero_class hero_class )
{
	t_hero_data& hero = m_hero[hero_class];

    std::string class_text;
    class_text = format_string("%s  %s", get_class_name( hero_class ).c_str(), ::get_alignment_name(get_alignment(hero_class)).c_str() );

	m_current_hero.hero_class = hero_class;
	m_current_hero.is_male = hero.is_male;
	m_class_text->set_text( class_text.c_str() ); //get_class_name( hero_class ) );
	m_male_checkbox->set_pressed( hero.is_male );
	m_female_checkbox->set_pressed( !hero.is_male );
	m_cost_text->set_text( format_string( "%i", hero.cost ) );
	m_buy_button->enable( m_funds >= hero.cost );

    // Show selected highlight.
	t_screen_rect   rect = m_layout->find( get_keyword( hero_class ) + "_portrait" )->get_rect();
    if (is_spellcaster( hero_class ))
    {
	    m_selected_magic_ring->move( rect.top_left() - m_might_magic_offset );
	    m_selected_magic_ring->set_visible( true );
	    m_selected_might_ring->set_visible( false );
    }
    else
    {
	    m_selected_might_ring->move( rect.top_left() - m_might_magic_offset );
	    m_selected_might_ring->set_visible( true );
	    m_selected_magic_ring->set_visible( false );
    }
                
	change_portrait();
	
	// set skill icons
	std::vector<t_skill> const& starting_skills = get_starting_skills( hero_class );

	// get new icons
	int                i;

	for (i = 0; i < starting_skills.size(); i++)
	{
		m_skill_icons[i]->set_skill( starting_skills[i] );
		m_skill_icons[i]->set_visible( true );
	}

	while (i < 3)
	{
		m_skill_icons[i]->set_visible( false );
		i++;
	}
}

// ---------------------------------------------------------
// dialog for hiring heroes
// ---------------------------------------------------------
void t_hire_hero_dialog::change_portrait()
{
	t_hero_data& hero = m_hero[m_current_hero.hero_class];

	m_current_hero = hero.heroes[hero.selected];

	t_bitmap_layer_ptr small_portrait;
	t_bitmap_layer_ptr large_portrait;
	
	small_portrait = get_hero_portrait( m_current_hero.portrait_id, 52 );
	large_portrait = get_hero_portrait( m_current_hero.portrait_id, 82 );
	hero.portrait_window->set_bitmap( small_portrait.get() );
	m_selected_portrait->set_bitmap( large_portrait.get() );
	hero.portrait = small_portrait;

	m_name_window->set_text( m_current_hero.name );
	m_biography_window->set_text( m_current_hero.biography );

	// Careful not to get selection changed if we change the size of the
	// scrollbar to be smaller than the current selection
	int selection = hero.selected;
	m_scrollbar->set_limits( 0, hero.heroes.size() - 1 );
	m_scrollbar->set_position( selection );
}

void t_hire_hero_dialog::name_change( t_text_edit_window* window )
{
	std::string old_name = m_current_hero.name;
	std::string old_biography = m_current_hero.biography;
	int			position;

	if (window->get_text().empty())
		return;

	m_current_hero.name = window->get_text();
	m_current_hero.biography = "";
	while (!old_biography.empty())
	{
		position = old_biography.find( old_name );
		if (position == old_biography.npos)
		{
			m_current_hero.biography += old_biography;
			break;
		}
		if (position > 0)
		{
			m_current_hero.biography += old_biography.substr( 0, position );
			old_biography.erase( 0, position );
		}
		m_current_hero.biography += m_current_hero.name;
		old_biography.erase( 0, old_name.length() );
	}
	m_biography_window->set_text( m_current_hero.biography );
}

void t_hire_hero_dialog::on_close()
{
	name_change( m_name_window );
}

// ---------------------------------------------------------
// dialog for hiring heroes
// ---------------------------------------------------------
void t_hire_hero_dialog::portrait_change( t_scrollbar* scrollbar, int value )
{
	t_hero_data& hero = m_hero[m_current_hero.hero_class];

	if (hero.selected == value)
		return;

	hero.selected = value;
	change_portrait();
}

// ---------------------------------------------------------
// dialog for hiring heroes
// ---------------------------------------------------------
void t_hire_hero_dialog::sex_selected( t_button* button, bool sex )
{
	if (!button->is_pressed())
		return;

	if (m_current_hero.is_male == sex)
		return;

	m_current_hero.is_male = sex;

	t_hero_data& hero = m_hero[m_current_hero.hero_class];

	hero.is_male = m_current_hero.is_male;
	hero.heroes = m_map.get_unused_heroes( m_current_hero.hero_class, hero.is_male );
	hero.selected = random( hero.heroes.size() );
	change_portrait();
}
